package com.sea.base.json

import com.google.gson.FieldNamingPolicy
import com.google.gson.GsonBuilder
import com.google.gson.JsonElement
import com.google.gson.JsonNull
import com.google.gson.internal.ConstructorConstructor
import com.google.gson.internal.Excluder
import com.google.gson.internal.bind.JsonAdapterAnnotationTypeAdapterFactory
import com.google.gson.internal.bind.MyReflectiveTypeAdapterFactory
import com.sea.base.json.typeAdapter.DefDoubleTypeAdapter
import com.sea.base.json.typeAdapter.DefIntegerTypeAdapter
import com.sea.base.json.typeAdapter.DefLongTypeAdapter
import com.sea.base.json.typeAdapter.DefShortTypeAdapter
import com.sea.base.json.typeAdapter.DefStringTypeAdapter
import com.sea.base.json.typeAdapter.StringCollectionTypeAdapterFactory
import retrofit2.converter.gson.GsonConverterFactory

/**
 * 注意：data class Test(val a: Int, val b: Int = 1)的默认值b无效（原因：没有无参构造），请全部加上默认值
 */
object Json {
    /**
     * 全局单列
     */
    internal val singleInstance = run {
        val intAdapter = DefIntegerTypeAdapter()
        val shortAdapter = DefShortTypeAdapter()
        val longAdapter = DefLongTypeAdapter()
        val doubleAdapter = DefDoubleTypeAdapter()
        val cc = ConstructorConstructor(emptyMap(), false, arrayListOf())
        GsonBuilder()
            .registerTypeAdapter(Int::class.java, intAdapter)
            .registerTypeAdapter(Int::class.javaPrimitiveType, intAdapter)
            .registerTypeAdapter(Short::class.java, shortAdapter)
            .registerTypeAdapter(Short::class.javaPrimitiveType, shortAdapter)
            .registerTypeAdapter(Long::class.java, longAdapter)
            .registerTypeAdapter(Long::class.javaPrimitiveType, longAdapter)
            .registerTypeAdapter(Double::class.java, doubleAdapter)
            .registerTypeAdapter(Double::class.javaPrimitiveType, doubleAdapter)
            .registerTypeAdapter(String::class.javaObjectType, DefStringTypeAdapter())
            //支持将字符串转成list等
            .registerTypeAdapterFactory(StringCollectionTypeAdapterFactory())
            //代理兜底的typeAdapter，如果后台返回null则不进行任何处理
            .registerTypeAdapterFactory(
                MyReflectiveTypeAdapterFactory(
                    cc,
                    FieldNamingPolicy.IDENTITY,
                    Excluder.DEFAULT,
                    JsonAdapterAnnotationTypeAdapterFactory(cc),
                    arrayListOf()
                )
            )
            .disableJdkUnsafe()
            .create()
    }

    /**
     * bean转String
     */
    @JvmStatic
    fun toJson(obj: Any?): String {
        return when (obj) {
            null -> ""
            is String -> obj
            is JsonNull -> ""
            is JsonElement -> singleInstance.toJson(obj)
            else -> singleInstance.toJson(obj)
        }
    }

    /**
     * bean转Map
     * @param obj bean或string
     */
    @JvmStatic
    fun toMap(obj: String?): Map<String, Any?>? = toMap(obj as Any?)

    @JvmStatic
    fun toMap(obj: Any?): Map<String, Any?>? {
        val jsonString = if (obj is String) obj else toJson(obj)
        return fromJson(jsonString, Map::class.java) as? Map<String, Any?>
    }

    //bean转list没有，因为list里可能是map或list，变化太多

    /**
     * string转bean
     */
    @JvmStatic
    fun <T> fromJson(json: String?, clazz: Class<T>): T? {
        if (json.isNullOrBlank()) {
            return null
        }
        return singleInstance.fromJson(json, clazz)
    }

    @JvmStatic
    inline fun <reified T> fromJson(json: String?): T? {
        return fromJson(json, T::class.java)
    }

    /**
     * map转bean
     */
    @JvmStatic
    fun <T> fromMap(map: Map<*, *>?, clazz: Class<T>): T? {
        return fromJson(toJson(map), clazz)
    }

    @JvmStatic
    inline fun <reified T> fromMap(map: Map<*, *>?): T? {
        return fromMap(map, T::class.java)
    }

    /**
     * string转list
     */
    @JvmStatic
    fun <T> fromJsonArray(json: String?, clazz: Class<T>): List<T> {
        if (json.isNullOrBlank()) {
            return arrayListOf()
        }
        return singleInstance.fromJson(json, ParameterizedTypeImpl(clazz)) ?: return arrayListOf()
    }

    @JvmStatic
    inline fun <reified T> fromJsonArray(json: String?): List<T> {
        return fromJsonArray(json, T::class.java)
    }

    /**
     * 任意list转list bean
     * 不建议用于copy或转换对象（建议自行实现深复制）
     */
    @JvmStatic
    fun <T> fromList(list: List<*>?, clazz: Class<T>): List<T> {
        return fromJsonArray(toJson(list), clazz)
    }

    @JvmStatic
    inline fun <reified T> fromList(list: List<*>?): List<T> {
        return fromJsonArray(toJson(list), T::class.java)
    }

    @JvmStatic
    fun newGsonConvertFactory() = GsonConverterFactory.create(singleInstance)
}